﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace AllenalaMente.Games.Selection
{
    public partial class Selection : UserControl, GameInterface
    {
        private DispatcherTimer updateTimer;
        private Random random;

        private int score;
        private int giuste, sbagliate;

        private int difficulty = 1;

        private UITimer gameTimer;

        private List<Item> items = new List<Item>();

        public Selection()
        {
            InitializeComponent();

            // Initalize game
            random = new Random();
            score = 0;
            textBlockScore.Text = score.ToString();

            // Update timer
            updateTimer = new DispatcherTimer();
            updateTimer.Interval = TimeSpan.FromMilliseconds(20);
            updateTimer.Tick += new EventHandler(Update);
            updateTimer.Start();

            // Eventi
            MouseMove += new MouseEventHandler(Puzzle_MouseMove);
            MouseLeftButtonUp += new MouseButtonEventHandler(Puzzle_MouseLeftButtonUp);

            // Game timer
            gameTimer = new UITimer(60);
            LayoutRoot.Children.Add(gameTimer);
            gameTimer.timeOut += new EventHandler(game_TimeOut);
            gameTimer.Start();

            CreateCombination();

            // Definisco l'area visualizzabile
            RectangleGeometry r = new RectangleGeometry();
            r.Rect = new Rect(0, 0, 800, 480);
            LayoutRoot.Clip = r;
        }

        #region Metodi

        private void CreateCombination()
        {
            for (int i = 0; i < 6; i++)
            {
                Item item = new Item(random.Next(2), new Point(340, (-100 * i)));
                //item.MouseLeftButtonDown += new MouseButtonEventHandler(item_MouseLeftButtonDown);
                canvasItem.Children.Add(item);
                Canvas.SetLeft(item, 340);
                Canvas.SetTop(item, (-100 * i));
                items.Add(item);
            }
        }

        private float speed = 2.0f, speedAmmount = 0.0f;

        private void Update(object sender, EventArgs e)
        {
            speed += speedAmmount;

            for (int i = 0; i < items.Count; i++)
            {
                if (!items[i].isBeingDragged)
                {
                    items[i].position.Y += (int)speed;
                    Canvas.SetTop(items[i], items[i].position.Y);

                    if (items[i].position.Y > 500)
                    {
                        int lasty = (int)items.Last().position.Y;

                        canvasItem.Children.Remove(items[i]);
                        items.RemoveAt(i);

                        Item item = new Item(random.Next(2), new Point(340,  lasty - 100));
                        canvasItem.Children.Add(item);
                        Canvas.SetLeft(item, 340);
                        Canvas.SetTop(item, -100);
                        items.Add(item);
                    }

                    items[i].textBlock1.Text = items[i].position.ToString();

                    if (items[i].Intersect(rectangle1))
                    {
                        if (items[i].type == 0) 
                        {
                            // Punti: 100 + (diff. lev * 10)
                            IncreaseScore(100 + (difficulty * 10)); 
                            giuste++;

                            if (giuste % 3 == 0) difficulty++;

                            if (giuste == 15) speedAmmount = 0.01f;
                            if (giuste == 45) speedAmmount = 0.05f;
                        }
                        
                        if (items[i].type == 1) { sbagliate++; }

                        int lasty = (int)items.Last().position.Y;

                        canvasItem.Children.Remove(items[i]);
                        items.Remove(items[i]);

                        Item item = new Item(random.Next(2), new Point(340, lasty - 100));
                        canvasItem.Children.Add(item);
                        Canvas.SetLeft(item, 340);
                        Canvas.SetTop(item, -100);
                        items.Add(item);

                        return;
                    }

                    if (items[i].Intersect(rectangle2))
                    {
                        if (items[i].type == 1) 
                        {
                            // Punti: 100 + (diff. lev * 10)
                            IncreaseScore(100 + (difficulty * 10)); 

                            giuste++;

                            if (giuste % 3 == 0) difficulty++;

                            if (giuste == 15) speedAmmount = 0.01f;
                            if (giuste == 45) speedAmmount = 0.05f;
                        }

                        if (items[i].type == 2) { sbagliate++; }

                        int lasty = (int)items.Last().position.Y;

                        canvasItem.Children.Remove(items[i]);
                        items.Remove(items[i]);

                        Item item = new Item(random.Next(2), new Point(340, lasty - 100));
                        canvasItem.Children.Add(item);
                        Canvas.SetLeft(item, 340);
                        Canvas.SetTop(item, -100);
                        items.Add(item);

                        return;
                    }
                }
            }
        }

        private void IncreaseScore(int amount)
        {
            score += amount;
            textBlockScore.Text = score.ToString();
        }

        private void DecreaseScore(int amount) 
        {
            score -= amount;
            if (score < 0) score = 0;

            textBlockScore.Text = score.ToString();
        }

        #endregion

        #region Animations

        public void Show(UIElement element)
        {
            DoubleAnimation doubleAnimation = new DoubleAnimation();
            doubleAnimation.From = 0;
            doubleAnimation.To = 1;
            doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(0.5));

            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Opacity"));
            Storyboard.SetTarget(doubleAnimation, element);

            Storyboard sb = new Storyboard();
            sb.Children.Add(doubleAnimation);
            sb.Begin();
        }

        public void hide(UIElement element)
        {
            DoubleAnimation doubleAnimation = new DoubleAnimation();
            doubleAnimation.From = 1;
            doubleAnimation.To = 0;
            doubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(1.0));

            Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("Opacity"));
            Storyboard.SetTarget(doubleAnimation, element);

            Storyboard sb = new Storyboard();
            sb.Children.Add(doubleAnimation);
            sb.Begin();
        }

        #endregion

        #region Eventi

        /// <summary>
        /// Se ci sono elementi da trascinare, li sposta sulla posizione del mouse
        /// </summary>
        private void Puzzle_MouseMove(object sender, MouseEventArgs e)
        {
            Point mousePointer = e.GetPosition(this);

            for (int i = 0; i < items.Count; i++)
            {
                if (items[i].isBeingDragged)
                    items[i].UpdatePosition(mousePointer);
            }
        }

        /// <summary>
        /// Al rilascio del pulsante sinistro, rilascia l'oggetto trascinato e controlla l'eventuale vittoria
        /// </summary>
        private void Puzzle_MouseLeftButtonUp(object sender, MouseEventArgs e)
        {
            // Al rilascio del pulsante sinistro, nessun pezzo deve essere più trascinato
            for (int i = 0; i < items.Count; i++)
                items[i].isBeingDragged = false;
        }

        public event GameEvent GameEnd;

        private void game_TimeOut(object sender, EventArgs e)
        {
            // Finito il tempo
            GameEventArgs gea = new GameEventArgs();
            gea.reason = GameCloseReason.Timeout;
            gea.score = this.score;
            gea.giuste = giuste;
            gea.sbagliate = sbagliate;

            if (GameEnd != null)
                GameEnd(this, gea);
        }

        #endregion        
    }
}
